/**
 * @file acl.cpp
 *
 * Copyright (C) Huawei Technologies Co., Ltd. 2019-2020. All Rights Reserved.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "acl/acl.h"

#include <memory>
#include <mutex>

#include "framework/executor/ge_executor.h"
#include "runtime/dev.h"
#include "runtime/stream.h"
#include "runtime/rt_preload_task.h"
#include "adx_datadump_server.h"
#include "common/util/error_manager/error_manager.h"

#include "log_inner.h"
#include "toolchain/plog.h"
#include "common_inner.h"
#include "model/acl_resource_manager.h"
#include "dump.h"
#include "profiling.h"
#include "error_codes_inner.h"
#include "toolchain/profiling_manager.h"
#include "toolchain/resource_statistics.h"
#include "graph/ge_local_context.h"
#include "acldvpp_init_for_acl_internal.h"
#include "platform/platform_info.h"
#include "utils/cann_info_utils.h"
#include "json_parser.h"
#include "register/stream_manage_func_registry.h"

namespace {
    bool aclInitFlag = false;
    bool aclFinalizeFlag = false;
    std::mutex aclInitMutex;
    std::mutex aclSocVersionMutex;
    std::string aclSocVersion;
    acl::GeFinalizeCallback aclGeFinalizeCallback = nullptr;
    bool isCastHasTruncateAttr = false;
    thread_local static std::string aclRecentErrMsg;
    bool isEnableDefaultDevice = false;
    constexpr int32_t INVALID_DEFAULT_DEVICE = -1;
    constexpr int32_t ACL_DEFAULT_DEVICE_DISABLE = 0xFFFFFFFF;
}

namespace acl {
void SetGeFinalizeCallback(const GeFinalizeCallback func)
{
    aclGeFinalizeCallback = func;
}

void SetThreadCompileOpts(const std::map<std::string, std::string> &options)
{
    // set thread local global option and clear session and graph options to avoid interference of graph mode options
    ge::GetThreadLocalContext().SetGlobalOption(options);
    ge::GetThreadLocalContext().SetSessionOption(std::map<std::string, std::string>{});
    ge::GetThreadLocalContext().SetGraphOption(std::map<std::string, std::string>{});
    return;
}

void SetCastHasTruncateAttr(const bool hasTruncate)
{
    isCastHasTruncateAttr = hasTruncate;
}

bool GetIfCastHasTruncateAttr()
{
    return isCastHasTruncateAttr;
}

aclError InitSocVersion()
{
    const std::unique_lock<std::mutex> lk(aclSocVersionMutex);
    if (aclSocVersion.empty()) {
        // get socVersion
        char_t socVersion[SOC_VERSION_LEN] = {};
        const auto rtErr = rtGetSocVersion(socVersion, static_cast<uint32_t>(sizeof(socVersion)));
        if (rtErr != RT_ERROR_NONE) {
            ACL_LOG_INFO("can not get soc version, runtime errorCode is %d", static_cast<int32_t>(rtErr));
            return ACL_GET_ERRCODE_RTS(rtErr);
        }
        aclSocVersion = std::string(socVersion);
    }
    ACL_LOG_INFO("get SocVersion success, SocVersion = %s", aclSocVersion.c_str());
    return ACL_SUCCESS;
}

const std::string &GetSocVersion()
{
    ACL_LOG_INFO("socVersion is %s", aclSocVersion.c_str());
    return aclSocVersion;
}

bool GetAclInitFlag()
{
    return aclInitFlag;
}

void aclGetMsgCallback(const char_t *msg, uint32_t len)
{
    if (msg == nullptr) {
        return;
    }
    (void)aclRecentErrMsg.assign(msg, static_cast<size_t>(len));
}

aclError GetPlatformInfoWithKey(const std::string &key, int64_t *value)
{
#ifdef __GNUC__
    // call after aclInit
    const string &socVersion = acl::GetSocVersion();

    // init platform info
    if (fe::PlatformInfoManager::GeInstance().InitializePlatformInfo() != 0U) {
        ACL_LOG_INNER_ERROR("init runtime platform info failed, SocVersion = %s", socVersion.c_str());
        return ACL_ERROR_INTERNAL_ERROR;
    }

    fe::PlatFormInfos platformInfos;
    fe::OptionalInfos optionalInfos;
    if (fe::PlatformInfoManager::GeInstance().GetPlatformInfos(socVersion, platformInfos, optionalInfos) != 0U) {
        ACL_LOG_INNER_ERROR("get platform info failed, SocVersion = %s", socVersion.c_str());
        return ACL_ERROR_INTERNAL_ERROR;
    }
    std::string strVal;
    if (!platformInfos.GetPlatformResWithLock("SoCInfo", key, strVal)) {
        ACL_LOG_CALL_ERROR("get platform result failed, key = %s", key.c_str());
        return ACL_ERROR_INTERNAL_ERROR;
    }

    try {
        *value = std::stoll(strVal);
    } catch (...) {
        ACL_LOG_INNER_ERROR("strVal[%s] can not be converted to digital value", strVal.c_str());
        return ACL_ERROR_INTERNAL_ERROR;
    }
    ACL_LOG_INFO("Successfully get platform info, key = %s, value = %ld", key.c_str(), *value);
#endif
    return ACL_SUCCESS;
}

int32_t UpdateOpSystemRunCfg(void *cfgAddr, uint32_t cfgLen)
{
    ACL_LOG_INFO("start to execute UpdateOpSystemRunCfg");
    if ((cfgAddr == nullptr) || (static_cast<size_t>(cfgLen) < sizeof(size_t))) {
        ACL_LOG_ERROR("UpdateOpSystemRunCfg failed, invalid config address(null) or invalid length %u.", cfgLen);
        return ACL_ERROR_RT_PARAM_INVALID;
    }

    // get device id
    int32_t devId = 0;
    auto rtErr = rtGetDevice(&devId);
    if (rtErr != RT_ERROR_NONE) {
        ACL_LOG_ERROR("can not get device id, runtime errorCode is %d", rtErr);
        return rtErr;
    }

    uint64_t offset = 0;
    // rts interface
    rtErr = rtGetL2CacheOffset(devId, &offset);
    if (rtErr != RT_ERROR_NONE) {
        if (rtErr == ACL_ERROR_RT_FEATURE_NOT_SUPPORT) {
            ACL_LOG_WARN("can not get l2 cache offset, feature not spport, device id = %d", devId);
        } else {
            ACL_LOG_ERROR("can not get l2 cache offset, runtime errorCode is %d, device id = %d", rtErr, devId);
        }
        return rtErr;
    }

    uint64_t *addr = static_cast<uint64_t *>(cfgAddr);
    *addr = offset;

    ACL_LOG_INFO("execute UpdateOpSystemRunCfg successfully, l2 cache offset is %lu, device id = %d", offset, devId);
    return ACL_RT_SUCCESS;
}

void HandleReleaseSourceByDevice(uint32_t devId, bool isReset)
{
    acl::AclResourceManager::GetInstance().HandleReleaseSourceByDevice(devId, isReset);
}

void HandleReleaseSourceByStream(aclrtStream stream, bool isCreate)
{
    acl::AclResourceManager::GetInstance().HandleReleaseSourceByStream(stream, isCreate);
}

aclError HandleErrorManagerConfig(const char_t *const configPath, error_message::ErrorMsgMode &error_mode) {
    const std::string ACL_ERR_MSG_CONFIG_NAME = "err_msg_mode";
    const std::string INTERNAL_MODE = "\"0\"";
    const std::string PROCESS_MODE = "\"1\"";
    error_mode = error_message::ErrorMsgMode::INTERNAL_MODE;

    if ((configPath != nullptr) && (strlen(configPath) != 0UL)) {
        std::string strConfig = PROCESS_MODE;
        bool found = false;
        auto ret = acl::JsonParser::GetJsonCtxByKey(configPath, strConfig, ACL_ERR_MSG_CONFIG_NAME, found);
        if (ret != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("can not parse err_msg config from file[%s], errorCode = %d", configPath, ret);
            return ret;
        }
        if (!found) {
            return ACL_SUCCESS;
        }
        ACL_LOG_INFO("err_msg mode is set [%s].", strConfig.c_str());
        if (strConfig == INTERNAL_MODE) {
            error_mode = error_message::ErrorMsgMode::INTERNAL_MODE;
        } else if (strConfig == PROCESS_MODE) {
            error_mode = error_message::ErrorMsgMode::PROCESS_MODE;
        } else {
            ACL_LOG_INNER_ERROR("err_msg mode config is invalid %s", strConfig.c_str());
            return ACL_ERROR_INVALID_PARAM;
        }
    }
    return ACL_SUCCESS;
}

aclError HandleDefaultDevice(const char_t *const configPath) {
    int32_t defaultDeviceId = INVALID_DEFAULT_DEVICE;
    auto ret = acl::JsonParser::GetDefaultDeviceIdFromFile(configPath, defaultDeviceId);
    if (ret != ACL_SUCCESS) {
        return ACL_ERROR_FAILURE;
    }
    if (defaultDeviceId == INVALID_DEFAULT_DEVICE) {
        return ACL_SUCCESS;
    }
    const auto rtErr = rtSetDefaultDeviceId(defaultDeviceId);
    if (rtErr != RT_ERROR_NONE) {
        ACL_LOG_CALL_ERROR("set default device id failed, ret:%d", rtErr);
        return ACL_GET_ERRCODE_RTS(rtErr);
    }
    isEnableDefaultDevice = true;
    ACL_LOG_INFO("set default device %d success\n", defaultDeviceId);
    return ACL_SUCCESS; 
}


bool IsEnableAutoUCMemeory()
{
    static const char_t *const autoUcMemory = std::getenv("AUTO_USE_UC_MEMORY");
    // enable: env is not exist or set to 1
    bool enable = ((autoUcMemory == nullptr) || (strlen(autoUcMemory) == 0UL) || (autoUcMemory[0] == '1'));
    ACL_LOG_INFO("auto-uc-memory is %s.", enable ? "enabled" : "disabled");
    return enable;
}
}

aclError aclInit(const char *configPath)
{
    ACL_STAGES_REG(acl::ACL_STAGE_INIT, acl::ACL_STAGE_DEFAULT);
    ACL_LOG_INFO("start to execute aclInit");
    acl::AclResourceManager::GetInstance().GetRuntimeV2Env();
    const std::unique_lock<std::mutex> lk(aclInitMutex);
    if (aclInitFlag) {
        ACL_LOG_INFO("repeatedly initialized");
        return ACL_ERROR_REPEAT_INITIALIZE;
    }

    error_message::ErrorMsgMode error_mode = error_message::ErrorMsgMode::INTERNAL_MODE;
    ACL_LOG_INFO("call ErrorManager.Initialize");
    auto ret = acl::HandleErrorManagerConfig(configPath, error_mode);
    if (ret != ACL_SUCCESS) {
        ACL_LOG_INNER_ERROR("[Process][ErrorMsg]process HandleErrorManagerConfig failed, ret=%d", ret);
        return ret;
    }

    ge::Status geRet = static_cast<ge::Status>(ErrorManager::GetInstance().Init(error_mode));
    if (geRet != ge::SUCCESS) {
        ACL_LOG_WARN("can not init ge errorManager, ge errorCode = %u", geRet);
    }
    if (DlogReportInitialize() != 0) {
        ACL_LOG_WARN("can not init device's log module");
    }

    if ((configPath != nullptr) && (strlen(configPath) != 0UL)) {
        // config dump
        ACL_LOG_INFO("set DumpConfig in aclInit");
        ret = acl::AclDump::GetInstance().HandleDumpConfig(configPath);
        if (ret != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Process][DumpConfig]process HandleDumpConfig failed");
            return ret;
        }
        ACL_LOG_INFO("set HandleDumpConfig success in aclInit");
        // config max_opqueue_num
        ACL_LOG_INFO("set max_opqueue_num in aclInit");
        ret = acl::AclResourceManager::GetInstance().HandleMaxOpQueueConfig(configPath);
        if (ret != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Process][QueueConfig]process HandleMaxOpQueueConfig failed");
            return ret;
        }
        ACL_LOG_INFO("set HandleMaxOpQueueConfig success in aclInit");
        ACL_LOG_INFO("set HandleDefaultDevice in aclInit");
        // parse configPath for defaultDevice and call rtSetDefaultDeviced
        ret = acl::HandleDefaultDevice(configPath);
        if (ret != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Process][DefaultDevice]process HandleDefaultDevice failed");
            return ret;
        }
        ACL_LOG_INFO("set HandleDefaultDevice success in aclInit");
    }
    const auto profRet = MsprofRegisterCallback(ASCENDCL, &acl::AclProfCtrlHandle);
    if (profRet != 0) {
        ACL_LOG_WARN("can not register Callback, prof result = %d", profRet);
    }
    // init GeExecutor
    ge::GeExecutor executor;
    ACL_LOG_INFO("call ge interface executor.Initialize");
    geRet = executor.Initialize();
    if (geRet != ge::SUCCESS) {
        ACL_LOG_CALL_ERROR("[Init][Geexecutor]init ge executor failed, ge errorCode = %u", geRet);
        return ACL_GET_ERRCODE_GE(static_cast<int32_t>(geRet));
    }

    // config profiling
    ACL_LOG_INFO("set ProfilingConfig in aclInit");
    ret = acl::AclProfiling::HandleProfilingConfig(configPath);
    if (ret != ACL_SUCCESS) {
        ACL_LOG_INNER_ERROR("[Process][ProfConfig]process HandleProfilingConfig failed");
        return ret;
    }
    // get socVersion
    ret = acl::InitSocVersion();
    if (ret != ACL_SUCCESS) {
        ACL_LOG_INNER_ERROR("[Init][Version]init soc version failed, ret = %d", ret);
        return ret;
    }

    // init acl dvpp
    if (acldvppInit != nullptr) {
        const acldvppStatus dvppRet = acldvppInit(nullptr);
        if (dvppRet != 0) {
            ACL_LOG_INNER_ERROR("[Init][acldvpp]init acl dvpp failed, ret = %d", dvppRet);
            return dvppRet;
        }
    }

    // register kernel launch fill function
    if (acl::IsEnableAutoUCMemeory()) {
        ACL_LOG_INFO("register kernel launch fill function in aclInit");
        auto rtRegErr = rtRegKernelLaunchFillFunc("g_opSystemRunCfg", acl::UpdateOpSystemRunCfg);
        if (rtRegErr != RT_ERROR_NONE) {
            if (rtRegErr == ACL_ERROR_RT_FEATURE_NOT_SUPPORT) {
                ACL_LOG_WARN("can not register kernel launch fill function, feature not spport.");
            } else {
                ACL_LOG_INNER_ERROR("[Init][RegFillFunc]register failed,ret = %d.", rtRegErr);
                return ACL_GET_ERRCODE_RTS(rtRegErr);
            }
        }
    }

    // register ge release function by stream
    auto rtErr = rtRegStreamStateCallback("ACL_MODULE_STREAM", &acl::HandleReleaseSourceByStream);
    if (rtErr != RT_ERROR_NONE) {
        ACL_LOG_INNER_ERROR("register release function by stream to runtime failed, ret:%d", rtErr);
        return ACL_GET_ERRCODE_RTS(rtErr);
    }

    // register ge release function by device
    rtErr= rtRegDeviceStateCallbackEx("ACL_MODULE_DEVICE", &acl::HandleReleaseSourceByDevice, DEV_CB_POS_FRONT);
    if (rtErr != RT_ERROR_NONE) {
        ACL_LOG_INNER_ERROR("register release function by device to runtime failed, ret:%d", rtErr);
        return ACL_GET_ERRCODE_RTS(rtErr);
    }

    aclInitFlag = true;
    ACL_LOG_INFO("successfully execute aclInit");
    return ACL_SUCCESS;
}

aclError aclFinalize()
{
    ACL_STAGES_REG(acl::ACL_STAGE_FINAL, acl::ACL_STAGE_DEFAULT);
    ACL_LOG_INFO("start to execute aclFinalize");
    const std::unique_lock<std::mutex> lk(aclInitMutex);
    if (aclFinalizeFlag) {
        ACL_LOG_INNER_ERROR("[Finalize][Acl]repeatedly finalized");
        return ACL_ERROR_REPEAT_FINALIZE;
    }
    if (DlogReportFinalize() != 0) {
        ACL_LOG_WARN("can not init device's log module");
    }
    acl::ResourceStatistics::GetInstance().TraverseStatistics();
    const int32_t profRet = MsprofFinalize();
    if (profRet != MSPROF_ERROR_NONE) {
        ACL_LOG_CALL_ERROR("[Finalize][Profiling]failed to call MsprofFinalize, prof errorCode = %d", profRet);
    }

    if (aclGeFinalizeCallback != nullptr) {
        const auto ret = aclGeFinalizeCallback();
        if (ret != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Finalize][Ge]ge finalize failed, errorCode = %d", static_cast<int32_t>(ret));
        }
    }

    // Finalize GeExecutor
    ge::GeExecutor executor;
    const ge::Status geRet = executor.Finalize();
    if (geRet != ge::SUCCESS) {
        ACL_LOG_CALL_ERROR("[Finalize][Ge]finalize ge executor failed, ge errorCode = %u", geRet);
        return ACL_GET_ERRCODE_GE(geRet);
    }

    if (acl::AclDump::GetInstance().GetAdxInitFromAclInitFlag()) {
        const int32_t adxRet = AdxDataDumpServerUnInit();
        if (adxRet != 0) {
            ACL_LOG_CALL_ERROR("[Generate][DumpFile]generate dump file failed in disk, adx errorCode = %d", adxRet);
            return ACL_ERROR_INTERNAL_ERROR;
        }
    }

    // finalize acl dvpp
    if (acldvppFinalize != nullptr) {
        const acldvppStatus dvppRet = acldvppFinalize();
        if (dvppRet != 0) {
            ACL_LOG_INNER_ERROR("[Finalize][acldvpp]finalize acl dvpp failed, ret = %d", dvppRet);
            return dvppRet;
        }
    }

    if (acl::IsEnableAutoUCMemeory()) {
        // unregister kernel launch fill function
        ACL_LOG_INFO("unregister kernel launch fill function in aclFinalize");
        auto rtRegErr = rtUnRegKernelLaunchFillFunc("g_opSystemRunCfg");
        if (rtRegErr != RT_ERROR_NONE) {
            if (rtRegErr == ACL_ERROR_RT_FEATURE_NOT_SUPPORT) {
                ACL_LOG_WARN("can not unregister kernel launch fill function, feature not spport.");
            } else {
                ACL_LOG_INNER_ERROR("Finalize][UnRegFillFunc]unregister failed,ret = %d.", rtRegErr);
                return ACL_GET_ERRCODE_RTS(rtRegErr);
            }
        }
    }

    // disable default device
    if (isEnableDefaultDevice) {
        ACL_LOG_INFO("disable default device");
        const auto rtErr = rtSetDefaultDeviceId(ACL_DEFAULT_DEVICE_DISABLE);
        if (rtErr != RT_ERROR_NONE) {
            ACL_LOG_WARN("close default device failed, ret:%d", rtErr);
            return ACL_GET_ERRCODE_RTS(rtErr);
        }
    }

    // unregister ge release function by stream
    auto rtErr = rtRegStreamStateCallback("ACL_MODULE_STREAM", nullptr);
    if (rtErr != RT_ERROR_NONE) {
        ACL_LOG_INNER_ERROR("unregister release function by stream to runtime failed, ret:%d", rtErr);
        return ACL_GET_ERRCODE_RTS(rtErr);
    }

    // unregister ge release function by device
    rtErr = rtRegDeviceStateCallbackEx("ACL_MODULE_DEVICE", nullptr, DEV_CB_POS_FRONT);
    if (rtErr != RT_ERROR_NONE) {
        ACL_LOG_INNER_ERROR("unregister release function by device to runtime failed, ret:%d", rtErr);
        return ACL_GET_ERRCODE_RTS(rtErr);
    }

    aclFinalizeFlag = true;
    ACL_LOG_INFO("successfully execute aclFinalize");
    return ACL_SUCCESS;
}

aclError aclrtGetVersion(int32_t *majorVersion, int32_t *minorVersion, int32_t *patchVersion)
{
    ACL_LOG_INFO("start to execute aclrtGetVersion.");
    ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(majorVersion);
    ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(minorVersion);
    ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(patchVersion);

    // Acl version is (*majorVersion).(*minorVersion).(*patchVersion)
    *majorVersion = ACL_MAJOR_VERSION;
    *minorVersion = ACL_MINOR_VERSION;
    *patchVersion = ACL_PATCH_VERSION;
    ACL_LOG_INFO("acl version is %d.%d.%d", *majorVersion, *minorVersion, *patchVersion);

    return ACL_SUCCESS;
}

const char *aclrtGetSocName()
{
    ACL_LOG_INFO("start to execute aclrtGetSocName.");
    // get socVersion
    const auto ret = acl::InitSocVersion();
    if (ret != ACL_SUCCESS) {
        ACL_LOG_INFO("can not init soc version, errorCode = %d", ret);
        return nullptr;
    }
    ACL_LOG_INFO("execute aclrtGetSocName successfully");
    return aclSocVersion.c_str();
}

static std::string GetFaultEventInfo()
{
    std::string faultInfo;

    int32_t deviceId = 0;
    auto ret = rtGetDevice(&deviceId);
    if (ret != RT_ERROR_NONE) {
        ACL_LOG_INFO("can not get device id, runtime errorCode is %d", static_cast<int32_t>(ret));
        return faultInfo;
    }

    rtDmsEventFilter filter = {};
    const uint32_t maxFaultNum = 128UL; // max is 128
    rtDmsFaultEvent faultEventInfo[maxFaultNum] = {};
    uint32_t eventCount = 0UL;
    ret = rtGetFaultEvent(deviceId, &filter, faultEventInfo, maxFaultNum, &eventCount);
    if (ret != RT_ERROR_NONE || eventCount == 0UL) {
        ACL_LOG_INFO("can not get fault event of device %d, runtime errorCode is %d",
            deviceId, static_cast<int32_t>(ret));
        return faultInfo;
    }

    for (uint32_t faultIndex = 0; faultIndex < eventCount; ++faultIndex) {
        std::ostringstream oss;
        oss << std::hex << faultEventInfo[faultIndex].eventId;
        faultInfo = faultInfo + "[0x" + oss.str() + "]"
            + faultEventInfo[faultIndex].eventName + ";";
    }

    if (faultInfo.empty()) {
        return faultInfo;
    }
    faultInfo = "Fault diagnosis analysis: " + faultInfo;
    return faultInfo;
}

const char *aclGetRecentErrMsg()
{
    ACL_LOG_INFO("start to execute aclGetRecentErrMsg.");
    constexpr const rtGetDevMsgType_t msgType = RT_GET_DEV_ERROR_MSG;
    const auto ret = rtGetDevMsg(msgType, &acl::aclGetMsgCallback);
    if (ret != RT_ERROR_NONE) {
        ACL_LOG_DEBUG("can not get device errorMessage, runtime errorCode is %d",
            static_cast<int32_t>(ret));
    }

    const std::string faultEventMsg = GetFaultEventInfo();
    if (!faultEventMsg.empty()) {
        if (aclRecentErrMsg.empty()) {
            aclRecentErrMsg = faultEventMsg;
        } else {
            aclRecentErrMsg = aclRecentErrMsg + "\n" + faultEventMsg;
        }
    }

    const std::string aclHostErrMsg = ErrorManager::GetInstance().GetErrorMessage();
    if ((aclHostErrMsg.empty()) && (aclRecentErrMsg.empty())) {
        ACL_LOG_DEBUG("get errorMessage is empty");
        return nullptr;
    }

    if (aclHostErrMsg.empty()) {
        return aclRecentErrMsg.c_str();
    }

    if (aclRecentErrMsg.empty()) {
        (void)aclRecentErrMsg.assign(aclHostErrMsg);
        return aclRecentErrMsg.c_str();
    }

    aclRecentErrMsg = aclHostErrMsg + "\n" + aclRecentErrMsg;
    ACL_LOG_INFO("execute aclGetRecentErrMsg successfully.");
    return aclRecentErrMsg.c_str();
}

aclError aclGetCannAttributeList(const aclCannAttr **cannAttrList, size_t *num)
{
    ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(cannAttrList);
    ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(num);
    const aclError ret = acl::CannInfoUtils::GetAttributeList(cannAttrList, num);
    if (ret != ACL_SUCCESS) {
        ACL_LOG_ERROR("failed to get attrList, ret = %d", ret);
        return ret;
    }
    ACL_LOG_INFO("execute aclGetCannAttributeList successfully.");
    return ACL_SUCCESS;
}

aclError aclGetCannAttribute(aclCannAttr cannAttr, int32_t *value)
{
    ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(value);
    const aclError ret = acl::CannInfoUtils::GetAttribute(cannAttr, value);
    if (ret != ACL_SUCCESS) {
        ACL_LOG_ERROR("failed to check, attr value = %d, ret = %d", static_cast<int32_t>(cannAttr), ret);
        return ret;
    }
    ACL_LOG_INFO("execute aclGetCannAttribute successfully.");
    return ACL_SUCCESS;
}

aclError aclGetDeviceCapability(uint32_t deviceId, aclDeviceInfo deviceInfo, int64_t *value)
{
    ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(value);
    int32_t count = -1;
    const rtError_t rtErr = rtGetDeviceCount(&count);
    if (rtErr != RT_ERROR_NONE) {
        ACL_LOG_CALL_ERROR("get device count failed, runtime result = %d.", static_cast<int32_t>(rtErr));
        return ACL_GET_ERRCODE_RTS(rtErr);
    }
    // currently check only, deviceId with [0, count - 1]
    ACL_CHECK_LESS_UINT(deviceId, static_cast<uint32_t>(count - 1));
    const std::map<aclDeviceInfo, std::string> infoTypeToKey = {
        {ACL_DEVICE_INFO_AI_CORE_NUM, "ai_core_cnt"},
        {ACL_DEVICE_INFO_VECTOR_CORE_NUM, "vector_core_cnt"},
        {ACL_DEVICE_INFO_L2_SIZE, "l2_size"}
    };
    const auto iter = infoTypeToKey.find(deviceInfo);
    if (iter == infoTypeToKey.end()) {
        ACL_LOG_WARN("get device info failed, invalid info type = %d", static_cast<int32_t>(deviceInfo));
        return ACL_ERROR_INVALID_PARAM;
    }
    const auto &key = iter->second;
    const aclError ret = acl::GetPlatformInfoWithKey(key, value);
    if (ret != ACL_SUCCESS) {
        ACL_LOG_ERROR("get device info failed, info type = %d, key = %s", static_cast<int32_t>(deviceInfo), key.c_str());
        return ret;
    }
    ACL_LOG_INFO("execute aclGetDeviceCapability successfully.");
    return ACL_SUCCESS;
}
